﻿using System.Runtime.InteropServices;

namespace ServiceCore.Utility.Extension
{
    public static class UtilityDateTime
    {
        #region 同步服务器时间到客户端

        [DllImport("Kernel32.dll")]
        public static extern bool SetLocalTime(ref SystemTime sysTime);

        public static bool SetLocalTimeByServer(this DateTime dt)
        {
            if (dt == DateTime.MinValue)
                return false;
            bool flag = false;
            SystemTime sysTime = new SystemTime();
            sysTime.wYear = Convert.ToUInt16(dt.Year);
            sysTime.wMonth = Convert.ToUInt16(dt.Month);
            sysTime.wDay = Convert.ToUInt16(dt.Day);
            sysTime.wHour = Convert.ToUInt16(dt.Hour);
            sysTime.wMinute = Convert.ToUInt16(dt.Minute);
            sysTime.wSecond = Convert.ToUInt16(dt.Second);
            try
            {
                flag = SetLocalTime(ref sysTime);
            }
            catch
            {
            }
            return flag;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct SystemTime
        {
            public ushort wYear;
            public ushort wMonth;
            public ushort wDayOfWeek;
            public ushort wDay;
            public ushort wHour;
            public ushort wMinute;
            public ushort wSecond;
            public ushort wMiliseconds;
        }

        #endregion 同步服务器时间到客户端

        #region 得到周几

        /// <summary>
        /// 得到周几
        /// </summary>
        /// <param name="dt"></param>
        /// <returns></returns>
        public static string GetWeek(this DateTime dt)
        {
            string type = dt.DayOfWeek.ToString();
            string week = "";
            switch (type)
            {
                case "Friday":
                    week = "星期五";
                    break;

                case "Monday":
                    week = "星期一";
                    break;

                case "Saturday":
                    week = "星期六";
                    break;

                case "Sunday":
                    week = "星期天";
                    break;

                case "Thursday":
                    week = "星期四";
                    break;

                case "Tuesday":
                    week = "星期二";
                    break;

                case "Wednesday":
                    week = "星期三";
                    break;
            }
            return week;
        }

        #endregion 得到周几

        #region 格式化日期时间为对应的字符串

        public static string ToyyyyMMddHHmmss(this DateTime dt)
        {
            return dt.ToString("yyyy-MM-dd HH:mm:ss");
        }

        public static string ToyyyyMMdd(this DateTime dt)
        {
            return dt.ToString("yyyy-MM-dd");
        }

        public static string ToyyMMddHHmm(this DateTime dt)
        {
            return dt.ToString("yy-MM-dd HH:mm");
        }

        public static string ToMMddHHmmss(this DateTime dt)
        {
            return dt.ToString("MM-dd HH:mm:ss");
        }

        public static string ToMMddHHmm(this DateTime dt)
        {
            return dt.ToString("MM-dd HH:mm");
        }

        public static string ToHHmm(this DateTime dt)
        {
            return dt.ToString("HH:mm");
        }

        public static string ToHHmmss(this DateTime dt)
        {
            return dt.ToString("HH:mm:ss");
        }

        public static string ToNumberAllDaTime(this DateTime dt)
        {
            return dt.ToString("yyyyMMddHHmmss");
        }

        public static decimal ToHHmmssNumber(this DateTime dt)
        {
            return decimal.Parse(dt.ToString("HHmmss"));
        }

        public static string ToyyyyMMddHHmmssffff(this DateTime dt)
        {
            return dt.ToString("yyyy-MM-dd HH:mm:ss.ffff");
        }

        #endregion 格式化日期时间为对应的字符串

        #region 得到时间间隔字符串描述

        /// <summary>
        /// 得到时间间隔字符串描述
        /// </summary>
        /// <param name="st"></param>
        /// <param name="now"></param>
        /// <returns></returns>
        public static string GetDuringStr(this DateTime st, DateTime? et = null, int minuteSub = 0)
        {
            if (et == null)
                et = DateTime.Now;
            return GetDuringStr(st, et.Value, minuteSub);
        }

        #endregion 得到时间间隔字符串描述

        private static string GetDuringStr(DateTime starttime, DateTime endtime, int minuteSub = 0)
        {
            string minus = "";
            TimeSpan sp = endtime - starttime;
            if (endtime < starttime)
            {
                sp = starttime - endtime;
                minus = "-";
            }

            int minutes = (int)((sp.TotalHours - (int)sp.TotalHours) * 60) + minuteSub;

            if (sp.TotalHours < 1)
                return minus + minutes.ToString() + "分";
            else
            {
                if (sp.TotalHours < 24)
                    return minus + (int)sp.TotalHours + "小时" + minutes.ToString() + "分";
                else
                {
                    double days = sp.TotalDays;
                    string dayformat = days.ToString("").Split('.')[0];
                    double hours = (days - (int)days) * 24;
                    string hourformat = hours.ToString("").Split('.')[0];
                    minutes = (int)((hours - (int)hours) * 60);
                    string minuteformat = minutes.ToString("").Split('.')[0];
                    return minus + dayformat + "天" + hourformat + "小时" + minuteformat + "分";
                }
            }
        }

        public static string GetDuringStrMinute(this DateTime endtime, DateTime starttime, int minuteSub = 0)
        {
            string minus = "";
            TimeSpan sp = endtime - starttime;
            if (endtime < starttime)
            {
                sp = starttime - endtime;
                minus = "-";
            }

            var abs = (int)Math.Abs(sp.TotalMinutes);
            if (abs >= 500)
                abs = 500;
            return minus + abs.ToString() + "'";
        }

        //DateTime类型转换为时间戳(毫秒值)
        public static long DateToTicks(this DateTime? time)
        {
            return ((time.HasValue ? time.Value.Ticks : DateTime.Parse("1990-01-01").Ticks) - 621355968000000000) / 10000;
        }

        public static long GetUnixTimeStamp(this DateTime dt)
        {
            DateTime dtStart = TimeZoneInfo.ConvertTimeFromUtc(new DateTime(1970, 1, 1, 0, 0, 0), TimeZoneInfo.Local);
            long timeStamp = Convert.ToInt32((dt - dtStart).TotalSeconds);
            return timeStamp;
        }

        //时间戳(毫秒值)String转换为DateTime类型转换
        public static DateTime TicksToDate(this long timestamp)
        {
            long begtime = timestamp * 10000000;
            DateTime dt_1970 = new DateTime(1970, 1, 1, 8, 0, 0);
            long tricks_1970 = dt_1970.Ticks;//1970年1月1日刻度
            long time_tricks = tricks_1970 + begtime;//日志日期刻度
            DateTime dt = new DateTime(time_tricks);//转化为DateTime
            return dt;
        }

        #region 只返回时间部分

        /// <summary>
        /// 只返回时间部分
        /// </summary>
        /// <param name="st"></param>
        /// <param name="et"></param>
        /// <returns></returns>
        public static TimeSpan ToTime(this string str)
        {
            var st = DateTime.Parse(str);
            var s = new TimeSpan(st.Hour, st.Minute, st.Second);
            return s;
        }

        #endregion 只返回时间部分

        #region 只返回时间部分

        /// <summary>
        /// 只返回时间部分
        /// </summary>
        /// <param name="st"></param>
        /// <param name="et"></param>
        /// <returns></returns>
        public static TimeSpan ToTime(this DateTime st)
        {
            var s = new TimeSpan(st.Hour, st.Minute, st.Second);
            return s;
        }

        #endregion 只返回时间部分

        #region 时间对比

        /// <summary>
        /// 时间对比
        /// </summary>
        /// <param name="st"></param>
        /// <param name="et"></param>
        /// <returns></returns>
        public static bool TimeCompare(this string Begin, string End, DateTime curtime)
        {
            var st = Begin.ToTime();
            var et = End.ToTime();

            var date = curtime.ToyyyyMMdd() + " ";
            if (st < et)
            {
                var s = DateTime.Parse(date + Begin);
                var e = DateTime.Parse(date + End);
                if (curtime >= s && curtime <= e)
                    return true;
            }
            else
            {
                var ct = curtime.ToHHmmss().ToTime();
                if (ct > st)
                {
                    return true;
                }
                else if (ct < et)
                {
                    return true;
                }
                else
                    return false;
            }
            return false;
        }

        #endregion 时间对比

        #region 时间对比_进店时间与离店时间必须在同一个时间范围内

        /// <summary>
        /// 时间对比_进店时间与离店时间必须在同一个时间范围内
        /// </summary>
        /// <param name="st"></param>
        /// <param name="et"></param>
        /// <returns></returns>
        public static bool TimeCompare(this string Begin, string End, DateTime stIn, DateTime etOut)
        {
            var st = Begin.ToTime();
            var et = End.ToTime();

            var date = stIn.ToyyyyMMdd() + " ";
            var s = DateTime.Parse(date + Begin);
            var e = DateTime.Parse(date + End);

            if (st < et)
            {
                if (stIn.Date != etOut.Date)
                    return false;

                if (stIn >= s && etOut <= e)
                    return true;
            }
            else
            {
                if ((etOut.Date - stIn.Date).TotalDays > 1 || (etOut.Date - stIn.Date).TotalDays < 0)
                    return false;

                if (stIn.Date == etOut.Date)
                {
                    var stintime = stIn.ToTime();
                    var etouttime = etOut.ToTime();

                    if (stintime > st && etouttime < "23:59:59".ToTime())
                        return true;
                    if (stintime > "00:00:00".ToTime() && etouttime < et)
                        return true;
                }
                else
                {
                    e = DateTime.Parse(stIn.Date.AddDays(1).ToyyyyMMdd() + " " + End);
                    var totalminute = (e - s).TotalMinutes;
                    var totalminuteComprare = (etOut - stIn).TotalMinutes;
                    if (totalminuteComprare > totalminute)
                        return false;

                    if (stIn.ToTime() > s.ToTime() && etOut.ToTime() < e.ToTime())
                        return true;
                }

            }
            return false;
        }

        #endregion 时间对比_进店时间与离店时间必须在同一个时间范围内

        #region 时间对比 begtime>end

        /// <summary>
        /// 时间对比 begtime>end
        /// </summary>
        /// <param name="st"></param>
        /// <param name="et"></param>
        /// <returns></returns>
        public static bool TimeCompareTwo(this string Begin, string End)
        {
            var st = Begin.ToTime();
            var et = End.ToTime();
            return st > et;
        }

        #endregion 时间对比 begtime>end

        #region 根据开始与结束时间点得到一个时间范围

        /// <summary>
        /// 根据开始与结束时间点得到一个时间范围
        /// </summary>
        /// <param name="st"></param>
        /// <param name="et"></param>
        /// <returns></returns>
        public static Tuple<DateTime, DateTime> TimeCompreCreateStAndEt(this string BeginTime, string EndTime)
        {
            var now = DateTime.Now;
            var dateNext = now.AddDays(1).ToyyyyMMdd() + " ";
            var dateLast = now.AddDays(-1).ToyyyyMMdd() + " ";
            var date = now.ToyyyyMMdd() + " ";
            var st = DateTime.Parse(date + BeginTime);
            var et = DateTime.Parse(date + EndTime);

            if (BeginTime.ToTime() > EndTime.ToTime())
            {
                if (now.ToTime() > BeginTime.ToTime())
                {
                    et = DateTime.Parse(dateNext + EndTime);
                }
                else
                {
                    st = DateTime.Parse(dateLast + BeginTime);
                }
            }

            return new Tuple<DateTime, DateTime>(st, et);
        }

        #endregion 根据开始与结束时间点得到一个时间范围
    }
}
